package eu.webhib.extgui.controller.tree;

import eu.webhib.extgui.controller.tree.data.ParentTreeDataProvider;
import eu.webhib.extgui.data.intf.DataItem;
import eu.webhib.extgui.data.intf.GuiParentChildEntity;
import eu.webhib.extgui.update.UpdateMngr;
import eu.webhib.extgui.data.service.intf.GuiParentChildService;
import org.apache.log4j.Logger;
import org.primefaces.event.NodeSelectEvent;
import org.primefaces.model.*;

/**
 * View controller managing the parent tree selection for an entity, e.g. in an the edit dialog.
 * The entity has a parent/child relationship.
 * Sets the parent of the edited data item as the selected tree node at build time and disables
 * the edit item since it should not allowed to select the item or its children as its parent.
 * @param T
 */
public class ParentTreeController<T extends GuiParentChildEntity<T>> extends TreeController {

   private static final Logger log = Logger.getLogger(ParentTreeController.class);
   /** the parent DataItem selected in the tree, is either the container label or an entity */
   protected DataItem parentTreeItem = null;
   /** shall be disabled (no children shown) in the tree and it is not selectable. This is an entity type */
   protected T disabledTreeItem = null;

   /**
    * Creates a tree control for the given treeItemProvider
    * @param treeItemProvider the tree item provider
    * @param updateMngr update of tree view components if needed
    * @param editDataItem the data item to be currently edited: this item will be disabled
    *                     and its parent is preselected in the tree
    */
   public ParentTreeController(ParentTreeDataProvider<T> treeItemProvider, UpdateMngr updateMngr, T editDataItem) {
      /** the currently edited item shall be disabled in the tree */
      super(treeItemProvider, updateMngr);
      /** the edit item is the one to be disabled */
      disabledTreeItem = editDataItem;
      if (editDataItem != null) {
         /** preselect the parent of the currently edited item */
         parentTreeItem = treeItemProvider.getViewParent(editDataItem);
      }
   }

   /**
    * Creates a tree controller with an default ParentTreeDataProvider
    * @param rootLabel label of the container root of the tree
    * @param entityService service providing the entities
    * @param updateMngr update of tree view components if needed
    * @param editDataItem the data item to be currently edited: this item will be disabled
    *                     and its parent is preselected in the tree
    */
   public ParentTreeController(String rootLabel, GuiParentChildService<T> entityService, UpdateMngr updateMngr, T editDataItem) {
      this(new ParentTreeDataProvider<T>(rootLabel, entityService), updateMngr, editDataItem);
   }

   /*
    * Get the entity the selected tree nodes represents
    */
   public T getParentEntity() {
      @SuppressWarnings("unchecked")
      T ret = (T) this.getSelectedEntity();
      return ret;
   }

   /**
    * Set the item to be disabled if any
    * @param editTreeItem item to be disabled or null
    */
   public void setDisabledTreeItem(T editTreeItem) {
      disabledTreeItem = editTreeItem;
   }


   /*
    * Set the parent item, the one selected after data rebuild, see buildData()
    */
   public void setParentTreeItem(DataItem parentTreeItem) {
      this.parentTreeItem = parentTreeItem;
   }

   /**
    * @see TreeController
    */
   @Override
   public void buildData() {
      super.buildData();
      if (parentTreeItem == null) {
         setRootSelected();
      } else {
         setSelectedTreeNodeByData(parentTreeItem);
      }
   }

   /**
    * Helper method to construct recursively the tree nodes based on and associated with the provided data items
    * @param dataItem holding the data item together with its children
    * @param treeNode the tree node associated with the dataItem parameter
    * @see TreeController
    */
   @Override
   protected void buildTree(DataItem dataItem, TreeNode treeNode) {
      log.trace("buildTree: " + dataItem);
      for (DataItem childItem : treeDataProvider.getViewChildren(dataItem)) {
         TreeNode childNode = new DefaultTreeNode(childItem, treeNode);
         /** suppress construction of all children of the disabled item */
         if (disabledTreeItem == null || !disabledTreeItem.identical(childItem)) {
            buildTree(childItem, childNode);
         }
      }
   }

   /**
    * Avoids selection of tree node holding the disabled data item
    * @see TreeController
    */
   @Override
   public void onNodeSelect(NodeSelectEvent event) {
      log.info("onNodeSelect: " + event.getTreeNode().getData().toString());
      /** tree node clicked by user */
      TreeNode clickedNode = event.getTreeNode();
      /** data item from tree node */
      DataItem clickedItem = (DataItem) clickedNode.getData();
      /** if node holds the data item to be the disabled one */
      if (clickedItem == disabledTreeItem) {
         /** undo node selection done by view framework */
         clickedNode.setSelected(false);
         selectedTreeNode.setSelected(true);
         /** because of programmatically changed selection, need to update the tree view */
         updateMngr.updateAll();
      } else {
         super.onNodeSelect(event);
      }
   }
}
